home *** CD-ROM | disk | FTP | other *** search
- /*
- * ADOC.YY -- Specification of the AUTODOC scanner
- *
- * (c)Copyright 1995 by Tobias Ferber, All Rights Reserved
- *
- * This file is part of ADOC.
- *
- * ADOC is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 1 of the License,
- * or (at your option) any later version.
- *
- * ADOC is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- /* $VER: $Id: adoc.yy,v 1.13 1995/03/20 18:44:10 tf Exp $ */
-
- %{
- #include <ctype.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdarg.h>
-
- #include "adoc.h"
- #include "libfun.h"
- #include "flist.h"
- #include "debug.h"
-
- /* In former versions of flex, yywrap had been defined as a macro */
-
- #ifdef yywrap
- #undef yywrap
- #endif
-
- /*
- ** local variables
- */
-
- /* scanner's error stream */
- static FILE *ferr;
-
- /* current input line (used for warnings and error messages) */
- static int scanner_line= 1;
-
- /* set to the line in this file if an error occurs */
- static int scanner_error= 0;
-
- /* name of the current input file */
- static char *scanner_infile= (char *)0;
-
- /* pedanticness of warning method */
- static int warn_mask;
-
- /* the last function which has been reported by funreport() */
- static char *report_fun= (char *)0;
-
- /* string containing allowed characters for the comment type */
- static char *fun_type;
-
- /*
- ** local functions
- */
-
- static void funreport(const char *fmt, ...)
- {
- va_list argp;
- va_start(argp,fmt);
- {
- char *fun= getfun( (char *)0 );
-
- if(fun) {
- if( !report_fun || strcmp(report_fun,fun) )
- fprintf(ferr,"%s: In function `%s':\n",scanner_infile,fun);
- }
- else { /* !fun */
- if(report_fun)
- fprintf(ferr,"%s: At top level:\n",scanner_infile);
- }
- report_fun= fun;
- }
- fprintf(ferr,"%s: %d: ",scanner_infile,scanner_line);
- vfprintf(ferr,(char *)fmt,argp);
- fprintf(ferr,"\n");
- fflush(ferr);
-
- va_end(argp);
- }
-
-
- /* Check the availability of section keywords in a function description.
- This procedure is called from the scanner at the end of a function */
-
- static void funcheck(int line, ...)
- {
- char *fun, *arg;
-
- va_list argp;
- va_start(argp,line);
-
- if( (fun= getfun((char *)0)) )
- {
- int missing= 0;
-
- for(arg= va_arg(argp, char *); arg && *arg; arg= va_arg(argp, char *))
- {
- if( !getsec(arg) )
- {
- if(missing)
- fprintf(ferr," `%s'",arg);
-
- else /* first missing keyword */
- {
- if( !report_fun || strcmp(report_fun,fun) )
- {
- fprintf(ferr,"%s: In function `%s':\n",scanner_infile,fun);
- report_fun= fun;
- }
- fprintf(ferr,"%s: %d: warning: missing keyword `%s'",scanner_infile,line,arg);
- }
-
- ++missing;
- }
- }
-
- if(missing)
- fprintf(ferr,"\n");
- }
- va_end(argp);
- }
-
- /* remove white spaces from the left and/or right end of a string `s' */
-
- static char *strip(char *s, char *lr)
- {
- char *l, *r, *t;
-
- if( strchr(lr,'l') )
- {
- /* find the first non-white char `l' in `s' */
- for(l=s; *l==' ' || *l=='\t'; l++) ;
- }
- else l=s;
-
- if( strchr(lr,'r') )
- {
- /* find the last non-white char `r' in `s' */
- for(t= r= l; *t; t++)
- {
- if(*t!=' ' && *t!='\t' && *t!='\r' && *t!='\n')
- r= t;
- }
-
- if(r[0])
- r[1]= '\0';
- }
-
- return l;
- }
-
- %}
-
- BLACK [^\n\r\f\t ]
- IDENT [a-zA-Z0-9\-_]+
- AST "*"
- NL (\r)|(\n)|(\r\n)|(\n\r)
-
- /* the context has been moved to the rule section
- because of problems with former versions of lex */
-
- FUN_BEGIN {BLACK}{AST}{3}.{2}{AST}{1}" "
- FUN_IDENT {IDENT}"/"{IDENT}
- FUN_SECTION {BLACK}[ \t]+[A-Z]{2}[A-Z ]*
- FUN_TEXT {BLACK}(([ \t].*)?)
- FUN_END {BLACK}{AST}{2}
-
- /*
- * eXclusive scanner modes:
- *
- * INITIAL skip source-code
- * EXPECT we just read a {FUN_BEGIN} and expect a {FUN_IDENT} now to enter <SKIP> mode
- * SKIP skip the rest of the line, then enter <FUN> mode
- * FUN collecting data in a comment section. {FUN_END} switches back to <INITIAL> mode again
- */
-
- %x EXPECT SKIP FUN
-
- %%
-
- <INITIAL>^{FUN_BEGIN} { if( strchr(fun_type,yytext[4]) || strchr(fun_type,yytext[5]) )
- {
- D(bug("line %ld: <%c%c>",scanner_line,yytext[4],yytext[5]));
- BEGIN(EXPECT);
- }
- }
-
- <EXPECT>{FUN_IDENT} { D(bug("BEGIN function `%s'",yytext));
-
- if( newfun(yytext) )
- {
- funreport("error adding function `%s' -- not enough memory?",yytext);
- return scanner_error= __LINE__;
- }
- BEGIN(SKIP);
- }
-
- <EXPECT>. { BEGIN(INITIAL); }
- <EXPECT>{NL} { ++scanner_line; BEGIN(INITIAL); }
-
- <SKIP>.*{NL} { yyless(yyleng-1); BEGIN(FUN); }
-
-
- /* There had been warnings because of a "dangerous trailing context"
- when using <FUN>^{FUN_SECTION}/{NL} and <FUN>^{FUN_TEXT}/{NL}.
-
- Note: we currently need the yyless() calls and put back the '\n' into
- the input to make sure the `^' in is recognized afterwards */
-
-
- <FUN>^{FUN_SECTION}{NL} { yyless(yyleng-1);
- { /* make a temporary copy of yytext */
- register char *t= strdup(&yytext[1]);
-
- if(t)
- {
- /* strip white chars on both sides of yytext */
- register char *s= strip(t,"lr");
- D(bug("... section `%s'",s));
-
- if( warn_mask & WARN_UNKNOWN_KEYWORDS )
- {
- if( !strarg(s,"NAME",
- "SYNOPSIS",
- "FUNCTION",
- "INPUTS",
- "RESULT",
- "EXAMPLE",
- "NOTES",
- "BUGS",
- "SEE ALSO", "") )
-
- funreport("warning: unknown section keyword `%s'",s);
- }
-
- if( newsec(s) )
- {
- funreport("error adding section keyword `%s' -- not enough memory?",s);
- return scanner_error= __LINE__;
- }
- free(t);
- }
- else /* !t */
- {
- funreport("ran out of memory");
- return scanner_error= __LINE__;
- }
- }
- }
-
- <FUN>^{FUN_TEXT}{NL} { yyless(yyleng-1);
- { /* make a temporary copy of yytext */
- register char *t= strdup(&yytext[1]);
-
- if(t)
- {
- /* remove trailing white spaces - especially the {NL} */
- register char *s= strip(t,"r");
-
- if( addtext(s) > 0 )
- {
- funreport("error adding text line -- not enough memory?");
- return scanner_error= __LINE__;
- }
-
- free(t);
- }
- else /* !t */
- {
- funreport("ran out of memory");
- return scanner_error= __LINE__;
- }
- }
- }
-
- <FUN>^{FUN_END}.*{NL} { D(bug("END function"));
-
- if( warn_mask & WARN_MISSING_KEYWORDS )
- {
- funcheck( scanner_line, "NAME",
- "SYNOPSIS",
- "FUNCTION",
- "INPUTS",
- "RESULT",
- "EXAMPLE",
- "NOTES",
- "BUGS",
- "SEE ALSO", "");
- }
- yyless(yyleng-1);
- BEGIN(INITIAL);
- }
-
- <FUN>^[ \t]*{NL} { if( warn_mask & WARN_BROKEN_COMMENTS )
- funreport("warning: broken autodoc comment");
- ++scanner_line;
- }
-
- <FUN>. { if( warn_mask & WARN_STRANGE_TEXT )
- funreport("warning: line does not match {FUN_TEXT}");
- }
-
- <INITIAL,EXPECT,SKIP,FUN>{NL} { scanner_line++; }
- <INITIAL,EXPECT,SKIP,FUN>. /* eat up anything else in <*> mode */
-
- <EXPECT,SKIP,FUN><<EOF>> { funreport("unexpected end of file");
- return scanner_error= __LINE__;
- }
-
- <INITIAL><<EOF>> { D(bug("%d lines at <<EOF>>",scanner_line));
- yyterminate();
- }
-
- %%
-
- /* This function opens the scanner stream for the file `fname' and
- initializes `scanner_infile' and `scanner_line' */
-
- static int init_scanner(char *fname)
- {
-
- #if !defined(USE_YYRESTART)
- static int num_calls= 0;
- #endif
-
- int result= 0;
-
- if(fname)
- {
- if(*fname)
- {
- FILE *fp= fopen(fname,"r");
-
- if(fp)
- {
- scanner_infile= fname;
-
- if(yyin && (yyin !=stdin))
- fclose(yyin);
-
- #if defined(USE_YYRESTART)
- yyrestart(fp);
- #else
- yyin= fp;
- if(++num_calls > 1) YY_NEW_FILE;
- #endif
- }
- else /* !fp */
- {
- fprintf(ferr,"scanner error: cannot read from `%s'\n",fname);
- scanner_error= __LINE__;
- result= 1;
- }
- }
- else /* !*fname */
- {
- scanner_infile= "stdin";
-
- if(yyin && (yyin !=stdin))
- fclose(yyin);
-
- #if defined(USE_YYRESTART)
- yyrestart(stdin);
- #else
- yyin= stdin;
- if(++num_calls > 1) YY_NEW_FILE;
- #endif
- }
- }
- else /* !fname */
- {
- scanner_infile= (char *)0;
- result= 1;
- }
-
- /* reset the line counter */
- scanner_line= 1;
-
- #ifdef DEBUG
- if(scanner_infile)
- D(bug("--> `%s'", scanner_infile));
- else
- D(bug("--> end of scanner input queue"));
- #endif DEBUG
-
- return result;
- }
-
- /* In former versions of flex, yywrap had been defined as a macro */
-
- #ifdef yywrap
- #undef yywrap
- #endif
-
- /*
- * yywrap() is called by yylex() each time the EOF is reached.
- * It returns 0 if there is another file to be scanned or
- * 1 if all scanning is done.
- * Our yywrap() will take the next file from the flist queue.
- */
-
- int yywrap()
- {
- int result= 1;
-
- if( !scanner_error )
- {
- flist_nextfile();
- result= init_scanner( flist_getname() );
- }
-
- return result;
- }
-
-
- int read_source(char *_fun_type, int _warn_mask)
- {
- int err= 0;
-
- D(bug_enter("read_source"));
-
- /* copy parameters to the local variables */
-
- fun_type = _fun_type;
- warn_mask = _warn_mask;
-
- /* initialize the error stream */
-
- ferr= get_ferr();
-
- /* initialize the scanner */
-
- if( init_scanner( flist_getname() ) == 0 )
- {
- if(scanner_error == 0)
- {
- /* yylex() returns an integer != 0 if an error occured. */
- err= yylex();
- }
- }
- else
- {
- D(bug("ooops!? filename queue is empty?"));
- }
-
- /* errors from yywrap() are returned as negative values */
-
- if(!err && scanner_error)
- err= -scanner_error;
-
- D(bug_leave("read_source (%s)",err ? "failed":"successful"));
-
- return err;
- }
-